<?php

namespace Illuminate\View;

use Illuminate\Support\ServiceProvider;
use Illuminate\View\Compilers\BladeCompiler;
use Illuminate\View\Engines\CompilerEngine;
use Illuminate\View\Engines\EngineResolver;
use Illuminate\View\Engines\FileEngine;
use Illuminate\View\Engines\PhpEngine;

/**
 * 视图服务提供者
 */
class ViewServiceProvider extends ServiceProvider
{
    /**
     * 注册服务
     *
     * @return void
     */
    public function register()
    {
        $this->registerFactory();

        $this->registerViewFinder();

        $this->registerEngineResolver();
    }

    /**
     * 注册视图工厂
     *
     * @return void
     */
    public function registerFactory()
    {
        $this->app->singleton('view', function ($app) {

            // 获取引擎解析器实例，该解析器将被应用于解析各种文件，比如 .php 和 .blade 文件
            $resolver = $app['view.engine.resolver'];

            $finder = $app['view.finder'];

            $factory = $this->createFactory($resolver, $finder, $app['events']);

            // 在视图环境中设置服务容器实例
            $factory->setContainer($app);

            $factory->share('app', $app);

            return $factory;
        });
    }

    /**
     * 创建一个视图工厂实例
     *
     * @param  \Illuminate\View\Engines\EngineResolver $resolver
     * @param  \Illuminate\View\ViewFinderInterface $finder
     * @param  \Illuminate\Contracts\Events\Dispatcher $events
     * @return \Illuminate\View\Factory
     */
    protected function createFactory($resolver, $finder, $events)
    {
        return new Factory($resolver, $finder, $events);
    }

    /**
     * 注册视图查找器的实现
     *
     * @return void
     */
    public function registerViewFinder()
    {
        $this->app->bind('view.finder', function ($app) {
            return new FileViewFinder($app['files'], $app['config']['view.paths']);
        });
    }

    /**
     * 注册 file/php/blade 视图引擎解析器
     *
     * @return void
     */
    public function registerEngineResolver()
    {
        $this->app->singleton('view.engine.resolver', function () {
            $resolver = new EngineResolver;

            // 接下来，我们将在解析器中注册各种视图引擎，以便执行环境根据视图文件的扩展来
            // 解析各种视图所需的引擎。我们为每个视图的引擎的注册调用一个方法。
            foreach (['file', 'php', 'blade'] as $engine) {
                $this->{'register' . ucfirst($engine) . 'Engine'}($resolver);
            }

            return $resolver;
        });
    }

    /**
     * 注册 file 引擎实现
     *
     * @param  \Illuminate\View\Engines\EngineResolver $resolver 引擎解析器
     * @return void
     */
    public function registerFileEngine($resolver)
    {
        $resolver->register('file', function () {
            return new FileEngine;
        });
    }

    /**
     * 注册 php 引擎实现
     *
     * @param  \Illuminate\View\Engines\EngineResolver $resolver 引擎解析器
     * @return void
     */
    public function registerPhpEngine($resolver)
    {
        $resolver->register('php', function () {
            return new PhpEngine;
        });
    }

    /**
     * 注册 Blade 引擎实现
     *
     * @param  \Illuminate\View\Engines\EngineResolver $resolver 引擎解析器
     * @return void
     */
    public function registerBladeEngine($resolver)
    {
        // Blade 引擎需要一个 CompilerInterface 实例才能正常工作，CompilerInterface 也就是 Blade 文件编译器，
        $this->app->singleton('blade.compiler', function () {
            return new BladeCompiler(
                $this->app['files'], $this->app['config']['view.compiled']
            );
        });

        $resolver->register('blade', function () {
            return new CompilerEngine($this->app['blade.compiler']);
        });
    }
}
